<template>
  <div class="image-compressor">
    <div class="image-compressor-container">
      <h1>图片压缩工具</h1>

      <!-- 上传区域 -->
      <div class="upload-area" @click="triggerFileInput" @drop.prevent="handleDrop" @dragover.prevent>
        <input type="file" ref="fileInput" accept="image/*" @change="handleFileChange" class="hidden-input" />
        <div v-if="!imageUrl" class="upload-placeholder">
          <i class="upload-icon">📁</i>
          <p>点击或拖拽图片到此处</p>
          <p class="support-text">支持: JPG, PNG, WEBP</p>
        </div>
      </div>

      <!-- 压缩设置 -->
      <div v-if="imageUrl" class="compression-settings">
        <div class="quality-slider">
          <span>压缩质量: {{ quality }}%</span>
          <input type="range" v-model="quality" min="1" max="100" @input="handleQualityChange" />
        </div>

        <!-- 图片预览区域 -->
        <div class="preview-container">
          <div class="preview-box">
            <h3>原图</h3>
            <img :src="imageUrl" alt="原图" class="preview-image" />
            <p>大小: {{ formatFileSize(originalSize) }}</p>
          </div>
          <div class="preview-box">
            <h3>压缩后</h3>
            <img :src="compressedImageUrl" alt="压缩后" class="preview-image" />
            <p>大小: {{ formatFileSize(compressedSize) }}</p>
          </div>
        </div>

        <!-- 下载按钮 -->
        <button v-if="compressedImageUrl" @click="downloadImage" class="download-btn">下载压缩后的图片</button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue'

const fileInput = ref(null)
const imageUrl = ref('')
const compressedImageUrl = ref('')
const quality = ref(80)
const targetSize = ref(0)
const originalSize = ref(0)
const compressedSize = ref(0)
const imageType = ref('')

// 触发文件选择
const triggerFileInput = () => {
  fileInput.value.click()
}

// 处理文件选择
const handleFileChange = (event) => {
  const file = event.target.files[0]
  if (file) {
    processImage(file)
  }
}

// 处理拖拽
const handleDrop = (event) => {
  const file = event.dataTransfer.files[0]
  if (file && file.type.startsWith('image/')) {
    processImage(file)
  }
}

// 处理图片
const processImage = (file) => {
  originalSize.value = file.size
  targetSize.value = originalSize.value * (quality.value / 100)
  imageType.value = file.type

  const reader = new FileReader()
  reader.onload = (e) => {
    imageUrl.value = e.target.result
    compressImage(e.target.result)
  }
  reader.readAsDataURL(file)
}

// 处理质量变化
const handleQualityChange = async () => {
  if (!imageUrl.value) return

  // 直接使用质量值进行压缩，不再使用二分查找
  const result = await testCompression(imageUrl.value, quality.value / 100)
  compressedImageUrl.value = result.dataUrl
  compressedSize.value = result.size
}

// 测试压缩结果
const testCompression = (src, testQuality) => {
  return new Promise((resolve) => {
    const img = new Image()
    img.src = src

    img.onload = () => {
      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')

      // 设置画布尺寸为原图尺寸
      canvas.width = img.width
      canvas.height = img.height

      // 清空画布并绘制图片
      ctx.clearRect(0, 0, canvas.width, canvas.height)
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height)

      // 根据原始图片类型选择压缩格式
      let mimeType = imageType.value
      if (!mimeType || mimeType === 'image/octet-stream') {
        if (src.startsWith('data:image/png')) {
          mimeType = 'image/png'
        } else if (src.startsWith('data:image/webp')) {
          mimeType = 'image/webp'
        } else {
          mimeType = 'image/jpeg'
        }
      }

      // 对于 PNG 格式的特殊处理
      if (mimeType === 'image/png') {
        // PNG 使用无损压缩，quality 参数无效，所以这里我们通过降低分辨率来实现压缩
        if (testQuality < 1) {
          const scale = Math.max(0.1, testQuality)
          const newWidth = Math.floor(img.width * scale)
          const newHeight = Math.floor(img.height * scale)

          // 创建临时画布进行缩放
          const tempCanvas = document.createElement('canvas')
          tempCanvas.width = newWidth
          tempCanvas.height = newHeight
          const tempCtx = tempCanvas.getContext('2d')
          tempCtx.drawImage(img, 0, 0, newWidth, newHeight)

          // 将缩放后的图像绘制回原画布
          ctx.clearRect(0, 0, canvas.width, canvas.height)
          canvas.width = newWidth
          canvas.height = newHeight
          ctx.drawImage(tempCanvas, 0, 0)
        }
      }

      // 转换为 base64
      const dataUrl = canvas.toDataURL(mimeType, testQuality)
      const base64str = dataUrl.split(',')[1]
      const size = Math.ceil(base64str.length * 0.75)

      resolve({ size, dataUrl })
    }
  })
}

// 压缩图片
const compressImage = async (src) => {
  // 直接使用当前质量值压缩
  const result = await testCompression(src, quality.value / 100)
  compressedImageUrl.value = result.dataUrl
  compressedSize.value = result.size
}

// 使用防抖优化频繁的质量调整
const debouncedQualityChange = (() => {
  let timer
  return () => {
    clearTimeout(timer)
    timer = setTimeout(() => {
      handleQualityChange()
    }, 100)
  }
})()

// 监听质量变化
watch(quality, () => {
  debouncedQualityChange()
})

// 格式化文件大小
const formatFileSize = (bytes) => {
  if (bytes === 0) return '0 Bytes'
  const k = 1024
  const sizes = ['Bytes', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

// 下载压缩后的图片
const downloadImage = () => {
  const link = document.createElement('a')
  // 根据原始图片类型设置文件扩展名
  const extension = imageType.value.split('/')[1] || 'jpg'
  link.download = `compressed-image.${extension}`
  link.href = compressedImageUrl.value
  link.click()
}
</script>

<style scoped>
.image-compressor {
  width: 100%;
  height: 100%;
  overflow-y: scroll;
}

.image-compressor-container {
  max-width: 1000px;
  margin: 0 auto;
  padding: 30px;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  margin-top: 20px;
}

.image-compressor h1 {
  text-align: center;
  color: #2c3e50;
  font-size: 28px;
  margin-bottom: 30px;
  font-weight: 600;
}

.upload-area {
  border: 2px dashed #e0e7ff;
  background: #f8faff;
  border-radius: 12px;
  padding: 50px 20px;
  text-align: center;
  cursor: pointer;
  margin: 20px 0;
  transition: all 0.3s ease;
}

.upload-area:hover {
  border-color: #6366f1;
  background: #f1f5ff;
  transform: translateY(-2px);
}

.hidden-input {
  display: none;
}

.upload-placeholder {
  color: #4b5563;
}

.upload-icon {
  font-size: 56px;
  margin-bottom: 16px;
  display: block;
  color: #6366f1;
}

.upload-placeholder p {
  margin: 8px 0;
  font-size: 16px;
}

.support-text {
  font-size: 14px;
  color: #6b7280;
  margin-top: 12px;
}

.compression-settings {
  margin-top: 30px;
  padding: 20px;
  background: #f8faff;
  border-radius: 12px;
  border: 1px solid #e0e7ff;
}

.quality-slider {
  margin: 25px 0;
  padding: 0 10px;
}

.quality-slider span {
  display: block;
  margin-bottom: 12px;
  color: #4b5563;
  font-weight: 500;
}

.quality-slider input[type='range'] {
  width: 100%;
  height: 6px;
  background: #e0e7ff;
  border-radius: 5px;
  outline: none;
  -webkit-appearance: none;
  margin-top: 15px;
}

.quality-slider input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px;
  height: 20px;
  background: #6366f1;
  border-radius: 50%;
  cursor: pointer;
  transition: all 0.2s ease;
  box-shadow: 0 2px 6px rgba(99, 102, 241, 0.3);
}

.quality-slider input[type='range']::-webkit-slider-thumb:hover {
  transform: scale(1.1);
  background: #4f46e5;
}

.preview-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 30px;
  margin: 30px 0;
}

.preview-box {
  background: white;
  padding: 20px;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  border: 1px solid #e5e7eb;
}

.preview-box h3 {
  color: #374151;
  font-size: 18px;
  font-weight: 600;
  margin-bottom: 15px;
}

.preview-image {
  max-width: 100%;
  max-height: 350px;
  object-fit: contain;
  border-radius: 8px;
  margin: 15px 0;
  background: #f9fafb;
  padding: 10px;
  border: 1px solid #e5e7eb;
}

.preview-box p {
  color: #6b7280;
  font-size: 14px;
  margin-top: 12px;
  font-weight: 500;
}

.download-btn {
  background-color: #6366f1;
  color: white;
  border: none;
  padding: 12px 24px;
  border-radius: 8px;
  cursor: pointer;
  font-size: 16px;
  font-weight: 500;
  transition: all 0.3s ease;
  display: block;
  margin: 20px auto 0;
  box-shadow: 0 2px 4px rgba(99, 102, 241, 0.2);
}

.download-btn:hover {
  background-color: #4f46e5;
  transform: translateY(-2px);
  box-shadow: 0 4px 6px rgba(99, 102, 241, 0.3);
}

.download-btn:active {
  transform: translateY(0);
}

@media (max-width: 768px) {
  .preview-container {
    grid-template-columns: 1fr;
  }

  .image-compressor {
    padding: 20px;
  }

  .upload-area {
    padding: 30px 15px;
  }
}
</style>
